# -*- coding:utf-8 -*-

from selenium import webdriver

'''
用程序实现极验验证码的识别过程

'''
# 1. 初始化
# EMAIL和PASSWORD就是登录极验需要的用户名和密码,需要先注册.
EMAIL = 'devops_yj@163.com'
PASSWORD = 'yuan666'

class CrackGeetest():
    def __init__(self):
        self.url = 'https://auth.geetest.com/login' # 极验管理后台登录页面
        self.browser = webdriver.Chrome()
        self.wait = WebDriverWait(self.browser,20)
        self.email = EMAIL
        self.password = PASSWORD

# 2. 模拟点击
'''
实现第一步的操作,也就是模拟点击初始的验证按钮. 我们定义一个方法来获取这个按钮,利用显式等待的方法来实现.
'''
def get_geetest_button(self):
    """
    获取初始验证按钮
    : return: 按钮对象.
    """
    button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'geetest_radar_tip')))
    return button
# 获取一个WebElement对象,调用它的click()方法即可模拟点击.
# 点击验证按钮
button = self.get_geetest_button()
button.click()


# 3. 识别缺口
'''
接下来识别缺口的位置,首先获取前后两张对比图片,二者不一致的地方即为缺口,获取不带缺口的图片,利用Selenium选取图片元素,得到其所在位置和宽高,然后获取整个网页的截图,图片裁切出来即可.
'''

def get_position(self):
    """
    获取验证码位置
    :return : 验证码位置元组.
    """
    img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME,'geetest_canvas_img')))
    time.sleep(2)
    location = img.location
    size = img.size
    top,bottom,left,right = location['y'],location['y'] + size['height'],location['x'],location['x'] + size['width']
    return (top,bottom,left,right)

def get_geetest_image(self,name='captcha.png'):
    """
    获取验证码图片
    :return: 图片对象
    """
    top, bottom,left,right = self.get_position()
    print('验证码位置',top,bottom,left,right)
    screenshot = self.get_screenshot()
    captcha = screenshot.crop((left,top,right,bottom))
    return captcha

'''
这里get_position()函数首先获取图片对象,获取它的位置和宽高,随后返回其左上角和右下角的坐标. get_geetest_image()方法获取网页截图,调用了crop()方法将图片裁切出来,返回的是Image对象.
接下来需要获取第二张图片,也就是带缺口的图片,要使得图片出现缺口,只需要点击下方的滑块即可,这个动作触发后,图片中的缺口就会显现.
'''
def get_slider(self):
    """
    获取滑块
    :return : 滑块对象.
    """
    slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'geetest_slider_button')))
    return slider
    # 利用get_slider()方法获取滑块对象,调用click()方法即可触发点击,缺口图片即可呈现.

# 点按呼出缺口
slider = self.get_slider()
slider.click()

'''
调用get_geetest_image()方法将第二张图片获取下来即可.

现在我们已经得到两张图片对象,分别赋值给变量image1和image2,接下来对比图片获取缺口.在这里遍历图片的每个坐标点,获取两张图片对应像素点的RGB数据. 如果二者的RGB数据差距在一定范围内,那就代表两个像素相同,继续比对下一个像素点。如果差距超过一定范围,则代表像素点不同,当前位置即为缺口位置. 代码实现如下:
'''

def is_pixel_equal(self,image1,image2,x,y):
    """
    判断两个像素是否相同
    :param image1: 图片1
    :param image2: 图片2
    :param x: 位置x
    :param y: 位置y
    :return: 像素是否相同.
    """

    # 取两个图片的像素点.
    pixel1 = image1.load()[x,y]
    pixel2 = image2.load()[x,y]
    threshold = 60
    if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(pixel1[2] - pixel2[2]) < threshold:
        return True
    else:
        return False

def get_gap(self,image1,image2):
    """
    获取缺口偏移量
    :param image1: 不带缺口图片
    :param image2: 带缺口图片
    :return:
    """
    left = 60
    for i in range(left,image1.size[0]):
        for j in range(image1.size[1]):
            if not self.is_pixel_equal(image1,image2,i,j):
                left = i
                return left
    return left

'''
get_gap()方法即获取缺口位置的方法. 此方法的参数是两张图片,一张为带缺口图片,另一张为不带缺口图片. 这里遍历两张图片的每个像素,利用is_pixel_equal()方法判断两张图片同一位置的像素是否相同. 比较两张图RGB的绝对值是否均小于定义的阈值threshold. 如果绝对值均在阈值之内,则代表像素点相同,继续遍历. 否则代表不相同的像素点,即缺口的位置.

两张图片有两处明显不同的地方: 一个就是待拼合的滑块,一个就是缺口.滑块的位置会出现在左边位置,缺口会出现在与滑块同一水平线的位置,所以缺口一般会在滑块的右侧,如果要寻找缺口,直接从滑块右侧寻找即可. 我们直接设置遍历的起始横坐标为60,也就是从滑块的右侧开始识别,这样识别出的结果就是缺口的位置.

现在,获取了缺口的位置,完成验证还剩下最后一步---模拟拖动.
'''

